package main

import (
	"fmt"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"os"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var db *gorm.DB

//sqlx 是对 sql 进行的一层封装
func initializeDatabase() (err error) {
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
		logger.Config{
			SlowThreshold:             time.Second, // 慢 SQL 阈值
			LogLevel:                  logger.Info, // 日志级别
			IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound（记录未找到）错误
			Colorful:                  true,        // 禁用彩色打印
		},
	)
	//data source name
	//用户名@密码@协议(ip:port)/数据库
	dsn := "root:123456@tcp(gincloud:3306)/gin_demo?charset=utf8mb4&parseTime=True&loc=Local"
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		//日志配置
		Logger: newLogger,
		//自定义表名格式
		NamingStrategy: schema.NamingStrategy{
			//自定义表名前缀
			TablePrefix: "t_",
			//单数模式(表名后不加s)
			SingularTable: true,
		},
	})
	if err != nil {
		panic(err)
	}
	return nil
}

//belongs to 会与另一个模型建立了一对一的连接
// `User` 属于 `Company`，`CompanyID` 是外键
type User struct {
	gorm.Model
	//直接使用 string 类型,那么数据库更新的时候不会更新空值
	//Name      string
	// *string 在数据库更新时是允许空值的, 或者使用 sql.NullString 类型(sql入参也需修改,相对繁琐)
	Name      *string
	CompanyID int
	//关联 Company
	Company Company
}

type Company struct {
	ID   int
	Name string
}

func main() {
	//连接数据库
	if err := initializeDatabase(); err != nil {
		panic(err)
	}
	fmt.Println("connected")

	// 迁移 schema(根据 Student 结构自动创建表)
	db.AutoMigrate(&User{})

	name := "nier"
	db.Create(&User{
		Name: &name,
		Company: Company{
			ID:   1,
			Name: "机械纪元",
		},
	})

	name = "2A"
	db.Create(&User{
		Name: &name,
		Company: Company{
			ID: 1,
		},
	})

	name = "2B"
	db.Create(&User{
		Name: &name,
		Company: Company{
			ID: 1,
		},
	})

	var user User
	//预加载关联的Company数据
	db.Preload("Company").First(&user)
	//查询user
	db.Find(&user)
	fmt.Println("user=", user)

	//更新(处理零值问题)
	empty := ""
	db.Model(&user).Updates(User{
		Name: &empty,
	})

	//物理删除: 使用 Unscoped()
	var userDel User
	db.Where("name = ?", "2B").First(&userDel)
	db.Unscoped().Delete(&userDel)

}
